
#include <BProgram>
#include <BMaterial>
#include <BTexture>
#include <BMatrix>
#include <BCamera>
#include <BViewer>
#include <BLight>
#include <BShape>
#include <BShape>
#include <BRender>
#include "member_BWidget.h"
#include "member_BRender.h"
#include "member_BNode.h"
#include "member_BShape.h"
#include "member_BShape.h"
#include "member_BProgram.h"
#include "member_BTexture.h"
#include "member_BMaterial.h"
#include "member_BCamera.h"

using namespace BWE;

#define member					(*(member_BRender*)_ptr)
#define member_allocate()		_ptr = new member_BRender(this)
#define member_release()		delete (member_BRender*)_ptr

BRender::BRender(BCamera* camera)
{
	member_allocate();
	member.save();
	member.camera = camera;
	if (!camera)
		return;

	const BSize& size = camera_member(camera)->pixelSize;
	glViewport(0, 0, size.width(), size.height());

	BVector position = camera->position();
	BVector center = camera->center();
	BVector up = camera->up();
	up.normalize();

	BMatrix modelViewMatrix;
	modelViewMatrix.lookAt(position, center, up);
	
	BReal lhw = camera->lensWidth() * 0.5;
	BReal lhh = camera->lensHeight() * 0.5;
	BReal near = camera->near();
	BReal far = camera->far();

	glBindFramebuffer(GL_FRAMEBUFFER, camera_member(camera)->fbo);
	glDrawBuffer(GL_COLOR_ATTACHMENT2);
	glReadBuffer(GL_COLOR_ATTACHMENT2);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if (camera->ortho())
		glOrtho(-lhw, lhw, -lhh, lhh, near, far);
	else
		glFrustum(-lhw, lhw, -lhh, lhh, near, far);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	BOpenGL::glLoadMatrix(modelViewMatrix);

	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

}
BRender::~BRender()
{
	member.open();
	member_release();
	glDisable(GL_DEPTH_TEST);
}

const BCamera* BRender::camera() const
{
	return member.camera;
}
const BNode* BRender::node() const
{
	return member.node;
}
const BShape* BRender::shape() const
{
	return member.shape;
}

void BRender::pushMatrix()
{
	glPushMatrix();
}
void BRender::popMatrix()
{
	glPopMatrix();
}

void BRender::pushAttrib()
{
	glPushAttrib(GL_ALL_ATTRIB_BITS);
}
void BRender::popAttrib()
{
	glPopAttrib();
}

void BRender::setMatrix(const BMatrix& matrix)
{
	member.matrix = matrix;
	BOpenGL::glMultMatrix(matrix);
}
const BMatrix& BRender::matrix() const
{
	return member.matrix;
}

void BRender::setColor(BByte r, BByte g, BByte b, BByte a)
{
	glColor4ub(r, g, b, a);
	member.color.set(r, g, b, a);
}
void BRender::setColor(const BColor& color)
{
	glColor4ub(color.r(), color.g(), color.b(), color.a());
	member.color = color;
}
const BColor& BRender::color() const
{
	return member.color;
}

void BRender::setLighting(bool lighting)
{
	if(lighting)
	{
		glEnable(GL_LIGHTING);
	}
	else
	{
		glDisable(GL_LIGHTING);
	}
	member.lighting = lighting;
}
bool BRender::lighting() const
{
	return member.lighting;
}

void BRender::setDepthTest(bool depthTest)
{
	if(depthTest)
	{
		glEnable(GL_DEPTH_TEST);
	}
	else
	{
		glDisable(GL_DEPTH_TEST);
	}
	member.depthTest = depthTest;
}
bool BRender::depthTest() const
{
	return member.depthTest;
}

void BRender::setCullback(bool cullback)
{
	if (cullback)
	{
		glEnable(GL_CULL_FACE);
		glCullFace(GL_BACK);
	}
	else
	{
		glDisable(GL_CULL_FACE);
	}
	member.cullback = cullback;
}
bool BRender::cullback() const
{
	return member.cullback;
}

void BRender::setLineSmooth(bool lineSmooth)
{
	member.lineSmooth = lineSmooth;
	if(lineSmooth)
	{
		glEnable(GL_LINE_SMOOTH);
	}
	else
	{
		glDisable(GL_LINE_SMOOTH);
	}
}
bool BRender::lineSmooth() const
{
	return member.lineSmooth;
}

void BRender::setLineWidth(int lineWidth)
{
	if(lineWidth <= 0)
		lineWidth = 1;
	glLineWidth((GLfloat)lineWidth);
	member.lineWidth = lineWidth;
}
int BRender::lineWidth() const
{
	return member.lineWidth;
}

void BRender::setLineStipple(BUShort stipple)
{
	if (member.lineStipple != stipple)
	{
		member.lineStipple = stipple;
		if (stipple > 0)
		{
			glEnable(GL_LINE_STIPPLE);
			glLineStipple(1, stipple);
		}
		else
		{
			glDisable(GL_LINE_STIPPLE);
		}
	}
}
BUShort BRender::stipple() const
{
	return member.lineStipple;
}

void BRender::setPointSmooth(bool pointSmooth)
{
	if (member.pointSmooth != pointSmooth)
	{
		member.pointSmooth = pointSmooth;
		if (pointSmooth)
			glEnable(GL_POINT_SMOOTH);
		else
			glDisable(GL_POINT_SMOOTH);
	}
}
bool BRender::pointSmooth() const
{
	return member.pointSmooth;
}

void BRender::setPointSize(int pointSize)
{
	if (pointSize <= 0)
		pointSize = 1;
	if (member.pointSize != pointSize)
	{
		member.pointSize = pointSize;
		glPointSize((GLfloat)pointSize);
	}
}
int BRender::pointSize() const
{
	return member.pointSize;
}

void BRender::setPolyMode(PolyMode polyMode)
{
	if (member.polyMode != polyMode)
	{
		member.polyMode = polyMode;
		switch (polyMode)
		{
		case Poly_Point:
			glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
			break;
		case Poly_Line:
			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
			break;
		case Poly_Fill:
			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
			break;
		}
	}
}
PolyMode BRender::polyMode() const
{
	return (PolyMode)member.polyMode;
}

void BRender::setPolygonSmooth(bool polygonSmooth)
{
	if (member.polygonSmooth != polygonSmooth)
	{
		member.polygonSmooth = polygonSmooth;
		if (polygonSmooth)
			glEnable(GL_POLYGON_SMOOTH);
		else
			glDisable(GL_POLYGON_SMOOTH);
	}
}
bool BRender::polygonSmooth() const
{
	return member.polygonSmooth;
}

void BRender::setPolygonOffset(float polygonOffset)
{
	if (member.polygonOffset != polygonOffset)
	{
		member.polygonOffset = polygonOffset;
		if (polygonOffset == 0)
		{
			glDisable(GL_POLYGON_OFFSET_POINT);
			glDisable(GL_POLYGON_OFFSET_LINE);
			glDisable(GL_POLYGON_OFFSET_FILL);
		}
		else
		{
			glEnable(GL_POLYGON_OFFSET_POINT);
			glEnable(GL_POLYGON_OFFSET_LINE);
			glEnable(GL_POLYGON_OFFSET_FILL);
			glPolygonOffset(polygonOffset, polygonOffset);
		}
	}
}
float BRender::polygonOffset() const
{
	return member.polygonOffset;
}

void BRender::setProgram(const BProgram* program)
{
	if (program && program->enabled())
	{
		bool ret = program_member(program)->use();
	}
	else
	{
		glUseProgram(0);
	}
}
void BRender::setMaterial(const BMaterial* material)
{
	if (material && material->enabled())
	{
		const BColorf& color0 = material_member(material)->ambientColor;
		const BColorf& color1 = material_member(material)->diffuseColor;
		const BColorf& color2 = material_member(material)->specularColor;
		const BColorf& color3 = material_member(material)->emissionColor;
		glMaterialfv(GL_FRONT, GL_AMBIENT, (const GLfloat*)&material_member(material)->ambientColor);
		glMaterialfv(GL_FRONT, GL_DIFFUSE, (const GLfloat*)&material_member(material)->diffuseColor);
		glMaterialfv(GL_FRONT, GL_SPECULAR, (const GLfloat*)&material_member(material)->specularColor);
		glMaterialfv(GL_FRONT, GL_EMISSION, (const GLfloat*)&material_member(material)->emissionColor);
		glMateriali(GL_FRONT, GL_SHININESS, (GLint)material->shininess());
	}
}
void BRender::setTexture(const BTexture* texture)
{
	if (texture && !texture->enabled())
		texture = 0;
	GLuint tbo = 0;
	if (texture)
	{
		if (texture_member(texture)->dirty)
			texture->flush();
		tbo = texture_member(texture)->tbo;
	}
	if (member.tbos[0] != tbo)
	{
		member.tbos[0] = tbo;
		if (tbo)
		{
			glActiveTexture(GL_TEXTURE0);
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, tbo);
			if (texture_member(texture)->blend == BTexture::Blend_Modulate)
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
			if (texture_member(texture)->blend == BTexture::Blend_Replace)
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
			if (texture_member(texture)->blend == BTexture::Blend_Decal)
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
			if (texture_member(texture)->blend == BTexture::Blend_Color)
			{
				const BColor& color = texture_member(texture)->blendColor;
				BColorf colorf(color.a() / 255.0f, color.g() / 255.0f, color.b() / 255.0f, color.a() / 255.0f);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
				glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&color);
			}
		}
		else
		{
			glBindTexture(GL_TEXTURE_2D, 0);
			glDisable(GL_TEXTURE_2D);
		}
	}
}
void BRender::setTexture(const BTexture* texture, int unit)
{
	if (unit < 0 || unit > 9)
		return;
	if (texture && !texture->enabled())
		texture = 0;
	GLuint tbo = 0;
	if (texture)
	{
		if (texture_member(texture)->dirty)
			texture->flush();
		tbo = texture_member(texture)->tbo;
	}
	if (member.tbos[unit] != tbo)
	{
		member.tbos[unit] = tbo;
		if (tbo)
		{
			glActiveTexture(GL_TEXTURE0 + unit);
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, tbo);
			if (texture_member(texture)->blend == BTexture::Blend_Modulate)
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
			if (texture_member(texture)->blend == BTexture::Blend_Replace)
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
			if (texture_member(texture)->blend == BTexture::Blend_Decal)
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
			if (texture_member(texture)->blend == BTexture::Blend_Color)
			{
				const BColor& color = texture_member(texture)->blendColor;
				BColorf colorf(color.a() / 255.0f, color.g() / 255.0f, color.b() / 255.0f, color.a() / 255.0f);
				glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
				glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&color);
			}
		}
		else
		{
			glBindTexture(GL_TEXTURE_2D, 0);
		}
		bool empty = true;
		for (int i = 0; i < 10; i++)
			if (member.tbos[i])
				empty = false;
		if (empty)
		{
			glDisable(GL_TEXTURE_2D);
		}
	}
}

void BRender::bind(const BWidget* widget)
{
	GLuint tbo = 0;
	if (widget)
	{
		if (widget_member(widget)->dirty)
		{
			widget_member(widget)->frame();
		}
		tbo = widget_member(widget)->tbo;
	}
	if (member.tbos[0] != tbo)
	{
		member.tbos[0] = tbo;
		if (tbo)
		{
			glEnable(GL_TEXTURE_2D);
			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, tbo);
		}
		else
		{
			glBindTexture(GL_TEXTURE_2D, 0);
			glDisable(GL_TEXTURE_2D);
		}
	}
}
void BRender::bind(const BCamera* camera)
{
	GLuint tbo = 0;
	if (camera)
	{
		tbo = camera_member(camera)->tbo;
	}
	if (member.tbos[0] != tbo)
	{
		member.tbos[0] = tbo;
		if (tbo)
		{
			glEnable(GL_TEXTURE_2D);
			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, tbo);
		}
		else
		{
			glBindTexture(GL_TEXTURE_2D, 0);
			glDisable(GL_TEXTURE_2D);
		}
	}
}
void BRender::unbind()
{
	bool changed = false;
	for (int i = 0; i < 10; i++)
	{
		if (member.tbos[i])
		{
			member.tbos[i] = 0;
			glActiveTexture(GL_TEXTURE0 + i);
			glBindTexture(GL_TEXTURE_2D, 0);
			changed = true;
		}
	}
	if (changed)
	{
		glDisable(GL_TEXTURE_2D);
	}
}

void BRender::drawPoint(float x, float y, float z)
{
	glBegin(GL_POINTS);
	glVertex3f(x, y, z);
	glEnd();
}
void BRender::drawPoint(double x, double y, double z)
{
	glBegin(GL_POINTS);
	glVertex3d(x, y, z);
	glEnd();
}

void BRender::drawPoint(const BVectorf& point)
{
	glBegin(GL_POINTS);
	glVertex3f(point.x(), point.y(), point.z());
	glEnd();
}
void BRender::drawPoint(const BVectord& point)
{
	glBegin(GL_POINTS);
	glVertex3d(point.x(), point.y(), point.z());
	glEnd();
}

void BRender::drawPoints(const BVectorf* points, int count)
{
	if (points && count > 0)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, points);
		glDrawArrays(GL_POINTS, 0, count);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::drawPoints(const BVectord* points, int count)
{
	if (points && count > 0)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, points);
		glDrawArrays(GL_POINTS, 0, count);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::drawPoints(const BVectorfArray& vertices)
{
	if (vertices.size())
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertices.data());
		glDrawArrays(GL_POINTS, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::drawPoints(const BVectordArray& vertices)
{
	if (vertices.size())
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, vertices.data());
		glDrawArrays(GL_POINTS, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}

void BRender::drawLine(const BLinef& line)
{
	glBegin(GL_LINES);
	glVertex3f(line.begin().x(), line.begin().y(), line.begin().z());
	glVertex3f(line.end().x(), line.end().y(), line.end().z());
	glEnd();
}
void BRender::drawLine(const BLined& line)
{
	glBegin(GL_LINES);
	glVertex3d(line.begin().x(), line.begin().y(), line.begin().z());
	glVertex3d(line.end().x(), line.end().y(), line.end().z());
	glEnd();
}
void BRender::drawLine(const BVectorf& begin, const BVectorf& end)
{
	glBegin(GL_LINES);
	glVertex3f(begin.x(), begin.y(), begin.z());
	glVertex3f(end.x(), end.y(), end.z());
	glEnd();
}
void BRender::drawLine(const BVectord& begin, const BVectord& end)
{
	glBegin(GL_LINES);
	glVertex3d(begin.x(), begin.y(), begin.z());
	glVertex3d(end.x(), end.y(), end.z());
	glEnd();
}
void BRender::drawLine(float x0, float y0, float z0, float x1, float y1, float z1)
{
	glBegin(GL_LINES);
	glVertex3f(x0, y0, z0);
	glVertex3f(x1, y1, z1);
	glEnd();
}
void BRender::drawLine(double x0, double y0, double z0, double x1, double y1, double z1)
{
	glBegin(GL_LINES);
	glVertex3d(x0, y0, z0);
	glVertex3d(x1, y1, z1);
	glEnd();
}

void BRender::drawLines(const BLinef* lines, int count)
{
	if (lines && count > 0)
	{
		for (int i = 0; i < count; i++)
		{
			drawLine(lines[i]);
		}
	}
}
void BRender::drawLines(const BLined* lines, int count)
{
	if (lines && count > 0)
	{
		for (int i = 0; i < count; i++)
		{
			drawLine(lines[i]);
		}
	}
}
void BRender::drawLines(const BLinefArray& lines)
{
	for (int i = 0; i < lines.size(); i++)
	{
		drawLine(lines[i]);
	}
}
void BRender::drawLines(const BLinedArray& lines)
{
	for (int i = 0; i < lines.size(); i++)
	{
		drawLine(lines[i]);
	}
}

void BRender::drawLines(const BVectorf* points, int size)
{
	if (points && size > 1)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, points);
		glDrawArrays(GL_LINES, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::drawLines(const BVectord* points, int size)
{
	if (points && size > 1)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, points);
		glDrawArrays(GL_LINES, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::drawLines(const BVectorfArray& vertices)
{
	if (vertices.size())
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertices.data());
		glDrawArrays(GL_LINES, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::drawLines(const BVectordArray& vertices)
{
	if (vertices.size())
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, vertices.data());
		glDrawArrays(GL_LINES, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}

void BRender::drawLineLoop(const BVectorf* vertexs, int size) const
{
	if(size < 3)
		return;
	glBegin(GL_LINE_LOOP);
	for(int i = 0; i < size; i++)
	{
		glVertex3f(vertexs[i].x(), vertexs[i].y(), vertexs[i].z());
	}
	glEnd();
}
void BRender::drawLineLoop(const BVectord* vertexs, int size) const
{
	if (size < 3)
		return;
	glBegin(GL_LINE_LOOP);
	for (int i = 0; i < size; i++)
	{
		glVertex3d(vertexs[i].x(), vertexs[i].y(), vertexs[i].z());
	}
	glEnd();
}
void BRender::drawLineLoop(const BVectorfArray& vertexs) const
{
	drawLineLoop(vertexs.data(), vertexs.size());
}
void BRender::drawLineLoop(const BVectordArray& vertexs) const
{
	drawLineLoop(vertexs.data(), vertexs.size());
}

void BRender::drawLineStrip(const BVectorf* points, int size) const
{
	if(size < 3)
		return;
	glBegin(GL_LINE_STRIP);
	for(int i = 0; i < size; i++)
	{
		glVertex3f(points[i].x(), points[i].y(), points[i].z());
	}
	glEnd();
}
void BRender::drawLineStrip(const BVectord* points, int size) const
{
	if (size < 2)
		return;
	glBegin(GL_LINE_STRIP);
	for (int i = 0; i < size; i++)
	{
		glVertex3d(points[i].x(), points[i].y(), points[i].z());
	}
	glEnd();
}
void BRender::drawLineStrip(const BVectorfArray& points) const
{
	drawLineStrip(points.data(), points.size());
}
void BRender::drawLineStrip(const BVectordArray& points) const
{
	drawLineStrip(points.data(), points.size());
}

void BRender::drawTriangle(const BTrianglef& triangle)
{
	const BVectorf& a = triangle.a();
	const BVectorf& b = triangle.b();
	const BVectorf& c = triangle.c();
	glBegin(GL_LINE_LOOP);
	glVertex3f(a.x(), a.y(), a.z());
	glVertex3f(b.x(), b.y(), b.z());
	glVertex3f(c.x(), c.y(), c.z());
	glEnd();
}
void BRender::drawTriangle(const BTriangled& triangle)
{
	const BVectord& a = triangle.a();
	const BVectord& b = triangle.b();
	const BVectord& c = triangle.c();
	glBegin(GL_LINE_LOOP);
	glVertex3d(a.x(), a.y(), a.z());
	glVertex3d(b.x(), b.y(), b.z());
	glVertex3d(c.x(), c.y(), c.z());
	glEnd();
}
void BRender::drawTriangle(const BVectorf& a, const BVectorf& b, const BVectorf& c)
{
	glBegin(GL_LINE_LOOP);
	glVertex3f(a.x(), a.y(), a.z());
	glVertex3f(b.x(), b.y(), b.z());
	glVertex3f(c.x(), c.y(), c.z());
	glEnd();
}
void BRender::drawTriangle(const BVectord& a, const BVectord& b, const BVectord& c)
{
	glBegin(GL_LINE_LOOP);
	glVertex3d(a.x(), a.y(), a.z());
	glVertex3d(b.x(), b.y(), b.z());
	glVertex3d(c.x(), c.y(), c.z());
	glEnd();
}

void BRender::drawTriangles(const BTrianglef* triangles, int count)
{
	for (int i = 0; i < count; i++)
	{
		const BTrianglef& tri = triangles[i];
		glBegin(GL_LINE_LOOP);
		glVertex3f(tri.a().x(), tri.a().y(), tri.a().z());
		glVertex3f(tri.b().x(), tri.b().y(), tri.b().z());
		glVertex3f(tri.c().x(), tri.c().y(), tri.c().z());
		glEnd();
	}
}
void BRender::drawTriangles(const BTriangled* triangles, int count)
{
	for (int i = 0; i < count; i++)
	{
		const BTriangled& tri = triangles[i];
		glBegin(GL_LINE_LOOP);
		glVertex3d(tri.a().x(), tri.a().y(), tri.a().z());
		glVertex3d(tri.b().x(), tri.b().y(), tri.b().z());
		glVertex3d(tri.c().x(), tri.c().y(), tri.c().z());
		glEnd();
	}
}
void BRender::drawTriangles(const BVectorf* points, int size)
{
	for (int i = 0; i < size; i += 3)
	{
		const BVectorf& a = points[i + 0];
		const BVectorf& b = points[i + 1];
		const BVectorf& c = points[i + 2];
		glBegin(GL_LINE_LOOP);
		glVertex3f(a.x(), a.y(), a.z());
		glVertex3f(b.x(), b.y(), b.z());
		glVertex3f(c.x(), c.y(), c.z());
		glEnd();
	}
}
void BRender::drawTriangles(const BVectord* points, int size)
{
	for (int i = 0; i < size; i += 3)
	{
		const BVectord& a = points[i + 0];
		const BVectord& b = points[i + 1];
		const BVectord& c = points[i + 2];
		glBegin(GL_LINE_LOOP);
		glVertex3d(a.x(), a.y(), a.z());
		glVertex3d(b.x(), b.y(), b.z());
		glVertex3d(c.x(), c.y(), c.z());
		glEnd();
	}
}
void BRender::drawTriangles(const BVectorfArray& vertices)
{
	for (int i = 0; i < vertices.size(); i += 3)
	{
		const BVectorf& a = vertices[i + 0];
		const BVectorf& b = vertices[i + 1];
		const BVectorf& c = vertices[i + 2];
		glBegin(GL_LINE_LOOP);
		glVertex3f(a.x(), a.y(), a.z());
		glVertex3f(b.x(), b.y(), b.z());
		glVertex3f(c.x(), c.y(), c.z());
		glEnd();
	}
}
void BRender::drawTriangles(const BVectordArray& vertices)
{
	for (int i = 0; i < vertices.size(); i += 3)
	{
		const BVectord& a = vertices[i + 0];
		const BVectord& b = vertices[i + 1];
		const BVectord& c = vertices[i + 2];
		glBegin(GL_LINE_LOOP);
		glVertex3d(a.x(), a.y(), a.z());
		glVertex3d(b.x(), b.y(), b.z());
		glVertex3d(c.x(), c.y(), c.z());
		glEnd();
	}
}

void BRender::fillTriangle(const BTrianglef& triangle)
{
	const BVectorf& a = triangle.a();
	const BVectorf& b = triangle.b();
	const BVectorf& c = triangle.c();
	glBegin(GL_TRIANGLES);
	if (member.lighting)
	{
		const BVectorf& n = triangle.normal();
		glNormal3f(n.x(), n.y(), n.z());
	}
	glVertex3f(a.x(), a.y(), a.z());
	glVertex3f(b.x(), b.y(), b.z());
	glVertex3f(c.x(), c.y(), c.z());
	glEnd();
}
void BRender::fillTriangle(const BTriangled& triangle)
{
	const BVectord& a = triangle.a();
	const BVectord& b = triangle.b();
	const BVectord& c = triangle.c();
	glBegin(GL_TRIANGLES);
	if (member.lighting)
	{
		const BVectord& n = triangle.normal();
		glNormal3d(n.x(), n.y(), n.z());
	}
	glVertex3d(a.x(), a.y(), a.z());
	glVertex3d(b.x(), b.y(), b.z());
	glVertex3d(c.x(), c.y(), c.z());
	glEnd();
}
void BRender::fillTriangle(const BVectorf& a, const BVectorf& b, const BVectorf& c)
{
	glBegin(GL_TRIANGLES);
	if (member.lighting)
	{
		BVectorf n = (c - a).cross(b - a);
		n.normalize();
		glNormal3f(n.x(), n.y(), n.z());
	}
	glVertex3f(a.x(), a.y(), a.z());
	glVertex3f(b.x(), b.y(), b.z());
	glVertex3f(c.x(), c.y(), c.z());
	glEnd();
}
void BRender::fillTriangle(const BVectord& a, const BVectord& b, const BVectord& c)
{
	glBegin(GL_TRIANGLES);
	if (member.lighting)
	{
		BVectord n = (c - a).cross(b - a);
		n.normalize();
		glNormal3d(n.x(), n.y(), n.z());
	}
	glVertex3d(a.x(), a.y(), a.z());
	glVertex3d(b.x(), b.y(), b.z());
	glVertex3d(c.x(), c.y(), c.z());
	glEnd();
}

void BRender::fillTriangles(const BVectorf* points, int size)
{
	if (points && size > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, points);
		glDrawArrays(GL_POLYGON, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillTriangles(const BVectord* points, int size)
{
	if (points && size > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, points);
		glDrawArrays(GL_POLYGON, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillTriangles(const BVectorfArray& vertices)
{
	if (vertices.size() > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertices.data());
		glDrawArrays(GL_TRIANGLES, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillTriangles(const BVectordArray& vertices)
{
	if (vertices.size() > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, vertices.data());
		glDrawArrays(GL_TRIANGLES, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}

void BRender::drawQuad(const BQuadf& quad)
{
	drawQuad(quad.a(), quad.b(), quad.c(), quad.d());
}
void BRender::drawQuad(const BQuadd& quad)
{
	drawQuad(quad.a(), quad.b(), quad.c(), quad.d());
}
void BRender::drawQuad(const BVectorf& a, const BVectorf& b, const BVectorf& c, const BVectorf& d)
{
	if (member.tbos[0])
	{
		glBegin(GL_LINE_LOOP);
			glTexCoord2f(0, 0);		glVertex3f(a.x(), a.y(), a.z());
			glTexCoord2f(1, 0);		glVertex3f(b.x(), b.y(), b.z());
			glTexCoord2f(1, 1);		glVertex3f(c.x(), c.y(), c.z());
			glTexCoord2f(0, 1);		glVertex3f(d.x(), d.y(), d.z());
		glEnd();
	}
	else
	{
		glBegin(GL_LINE_LOOP);
		glVertex3f(a.x(), a.y(), a.z());
		glVertex3f(b.x(), b.y(), b.z());
		glVertex3f(c.x(), c.y(), c.z());
		glVertex3f(d.x(), d.y(), d.z());
		glEnd();
	}
}
void BRender::drawQuad(const BVectord& a, const BVectord& b, const BVectord& c, const BVectord& d)
{
	if (member.tbos[0])
	{
		glBegin(GL_LINE_LOOP);
		glTexCoord2f(0, 0);		glVertex3d(a.x(), a.y(), a.z());
		glTexCoord2f(1, 0);		glVertex3d(b.x(), b.y(), b.z());
		glTexCoord2f(1, 1);		glVertex3d(c.x(), c.y(), c.z());
		glTexCoord2f(0, 1);		glVertex3d(d.x(), d.y(), d.z());
		glEnd();
	}
	else
	{
		glBegin(GL_LINE_LOOP);
		glVertex3d(a.x(), a.y(), a.z());
		glVertex3d(b.x(), b.y(), b.z());
		glVertex3d(c.x(), c.y(), c.z());
		glVertex3d(d.x(), d.y(), d.z());
		glEnd();
	}
}

void BRender::drawQuads(const BVectorf* points, int size)
{
	if (points && size > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, points);
		glDrawArrays(GL_QUADS, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
}
void BRender::drawQuads(const BVectord* points, int size)
{
	if (points && size > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, points);
		glDrawArrays(GL_QUADS, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
}
void BRender::drawQuads(const BVectorfArray& vertices)
{
	if (vertices.size() > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertices.data());
		glDrawArrays(GL_QUADS, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
}
void BRender::drawQuads(const BVectordArray& vertices)
{
	if (vertices.size() > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, vertices.data());
		glDrawArrays(GL_QUADS, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
}

void BRender::drawQuadStrip(const BVectorf* points, int size)
{
	if (points && size > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, points);
		glDrawArrays(GL_QUAD_STRIP, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
}
void BRender::drawQuadStrip(const BVectord* points, int size)
{
	if (points && size > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, points);
		glDrawArrays(GL_QUAD_STRIP, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
}
void BRender::drawQuadStrip(const BVectorfArray& vertices)
{
	if (vertices.size() > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertices.data());
		glDrawArrays(GL_QUAD_STRIP, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
}
void BRender::drawQuadStrip(const BVectordArray& vertices)
{
	if (vertices.size() > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, vertices.data());
		glDrawArrays(GL_QUAD_STRIP, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
}

void BRender::fillQuad(const BQuadf& quad)
{
	const BVectorf& a = quad.a();
	const BVectorf& b = quad.b();
	const BVectorf& c = quad.c();
	const BVectorf& d = quad.d();
	if (member.tbos[0])
	{
		glBegin(GL_QUADS);
		if (member.lighting)
		{
			const BVectorf& n = quad.normal();
			glNormal3f(n.x(), n.y(), n.z());
		}
		glTexCoord2f(0, 0);		glVertex3f(a.x(), a.y(), a.z());
		glTexCoord2f(0, 1);		glVertex3f(b.x(), b.y(), b.z());
		glTexCoord2f(1, 1);		glVertex3f(c.x(), c.y(), c.z());
		glTexCoord2f(1, 0);		glVertex3f(d.x(), d.y(), d.z());
		glEnd();
	}
	else
	{
		glBegin(GL_QUADS);
		if (member.lighting)
		{
			const BVectorf& n = quad.normal();
			glNormal3f(n.x(), n.y(), n.z());
		}
		glVertex3f(a.x(), a.y(), a.z());
		glVertex3f(b.x(), b.y(), b.z());
		glVertex3f(c.x(), c.y(), c.z());
		glVertex3f(d.x(), d.y(), d.z());
		glEnd();
	}
}
void BRender::fillQuad(const BQuadd& quad)
{
	const BVectord& a = quad.a();
	const BVectord& b = quad.b();
	const BVectord& c = quad.c();
	const BVectord& d = quad.d();
	if (member.tbos[0])
	{
		glBegin(GL_QUADS);
		if (member.lighting)
		{
			const BVectord& n = quad.normal();
			glNormal3d(n.x(), n.y(), n.z());
		}
		glTexCoord2f(0, 0);		glVertex3d(a.x(), a.y(), a.z());
		glTexCoord2f(0, 1);		glVertex3d(b.x(), b.y(), b.z());
		glTexCoord2f(1, 1);		glVertex3d(c.x(), c.y(), c.z());
		glTexCoord2f(1, 0);		glVertex3d(d.x(), d.y(), d.z());
		glEnd();
	}
	else
	{
		glBegin(GL_QUADS);
		if (member.lighting)
		{
			const BVectord& n = quad.normal();
			glNormal3d(n.x(), n.y(), n.z());
		}
		glVertex3d(a.x(), a.y(), a.z());
		glVertex3d(b.x(), b.y(), b.z());
		glVertex3d(c.x(), c.y(), c.z());
		glVertex3d(d.x(), d.y(), d.z());
		glEnd();
	}
}
void BRender::fillQuad(const BVectorf& a, const BVectorf& b, const BVectorf& c, const BVectorf& d)
{
	if (member.tbos[0])
	{
		glBegin(GL_QUADS);
		if (member.lighting)
		{
			BVector n = (c - a).cross(b - a);
			n.normalize();
			BOpenGL::glNormal(n.x(), n.y(), n.z());
		}
		glTexCoord2f(0, 0);		glVertex3f(a.x(), a.y(), a.z());
		glTexCoord2f(0, 1);		glVertex3f(b.x(), b.y(), b.z());
		glTexCoord2f(1, 1);		glVertex3f(c.x(), c.y(), c.z());
		glTexCoord2f(1, 0);		glVertex3f(d.x(), d.y(), d.z());
		glEnd();
	}
	else
	{
		glBegin(GL_QUADS);
		if (member.lighting)
		{
			BVector n = (c - a).cross(b - a);
			n.normalize();
			BOpenGL::glNormal(n.x(), n.y(), n.z());
		}
		glVertex3f(a.x(), a.y(), a.z());
		glVertex3f(b.x(), b.y(), b.z());
		glVertex3f(c.x(), c.y(), c.z());
		glVertex3f(d.x(), d.y(), d.z());
		glEnd();
	}
}
void BRender::fillQuad(const BVectord& a, const BVectord& b, const BVectord& c, const BVectord& d)
{
	if (member.tbos[0])
	{
		glBegin(GL_QUADS);
		if (member.lighting)
		{
			BVectord n = (c - a).cross(b - a);
			n.normalize();
			glNormal3d(n.x(), n.y(), n.z());
		}
		glTexCoord2f(0, 0);		glVertex3d(a.x(), a.y(), a.z());
		glTexCoord2f(0, 1);		glVertex3d(b.x(), b.y(), b.z());
		glTexCoord2f(1, 1);		glVertex3d(c.x(), c.y(), c.z());
		glTexCoord2f(1, 0);		glVertex3d(d.x(), d.y(), d.z());
		glEnd();
	}
	else
	{
		glBegin(GL_QUADS);
		if (member.lighting)
		{
			BVectord n = (c - a).cross(b - a);
			n.normalize();
			glNormal3d(n.x(), n.y(), n.z());
		}
		glVertex3d(a.x(), a.y(), a.z());
		glVertex3d(b.x(), b.y(), b.z());
		glVertex3d(c.x(), c.y(), c.z());
		glVertex3d(d.x(), d.y(), d.z());
		glEnd();
	}
}

void BRender::fillQuads(const BVectorf* points, int size)
{
	if (points && size > 3)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, points);
		glDrawArrays(GL_QUADS, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillQuads(const BVectord* points, int size)
{
	if (points && size > 3)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, points);
		glDrawArrays(GL_QUADS, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillQuads(const BVectorfArray& vertices)
{
	if (vertices.size() > 3)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertices.data());
		glDrawArrays(GL_QUADS, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillQuads(const BVectordArray& vertices)
{
	if (vertices.size() > 3)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, vertices.data());
		glDrawArrays(GL_QUADS, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}

void BRender::fillQuadStrip(const BVectorf* points, int size)
{
	if (points && size > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, points);
		glDrawArrays(GL_QUAD_STRIP, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillQuadStrip(const BVectord* points, int size)
{
	if (points && size > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, points);
		glDrawArrays(GL_QUAD_STRIP, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillQuadStrip(const BVectorfArray& vertices)
{
	if (vertices.size() > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertices.data());
		glDrawArrays(GL_QUAD_STRIP, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillQuadStrip(const BVectordArray& vertices)
{
	if (vertices.size() > 3)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, vertices.data());
		glDrawArrays(GL_QUAD_STRIP, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}

void BRender::drawCircle(const BCirclef& circle)
{
	const BVectorfArray& vertexs = circle.vertexs();
	drawLineLoop(vertexs);
}
void BRender::drawCircle(const BCircled& circle)
{
	const BVectordArray& vertexs = circle.vertexs();
	drawLineLoop(vertexs);
}
void BRender::drawCircle(const BVectorf& center, float radius, int side, const BVectorf& normal)
{
	BQuaterf quater(BVectorf(0, 0, 1), normal);
	float step = PI2f / side;
	glBegin(GL_LINE_LOOP);
	for (int i = 0; i < side; i++)
	{
		float x = cos(i * step) * radius;
		float y = sin(i * step) * radius;
		BVectorf vertex = BVectorf(x, y, 0) * quater + center;
		glVertex3f(vertex.x(), vertex.y(), vertex.z());
	}
	glEnd();
}
void BRender::drawCircle(const BVector& center, double radius, int side, const BVectord& normal)
{
	BQuaterd quater(BVectord(0, 0, 1), normal);
	double step = PI2 / side;
	glBegin(GL_LINE_LOOP);
	for (int i = 0; i < side; i++)
	{
		double x = cos(i * step) * radius;
		double y = sin(i * step) * radius;
		BVectord vertex = BVectord(x, y, 0) * quater + center;
		glVertex3d(vertex.x(), vertex.y(), vertex.z());
	}
	glEnd();
}

void BRender::fillCircle(const BCirclef& circle)
{
	const BVectorfArray& vertexs = circle.vertexs();
	drawPolygon(vertexs);
}
void BRender::fillCircle(const BCircled& circle)
{
	const BVectordArray& vertexs = circle.vertexs();
	fillPolygon(vertexs);
}
void BRender::fillCircle(const BVectorf& center, float radius, int side, const BVectorf& normal)
{
	BQuaterf quater(BVectorf(0, 0, 1), normal);
	float step = PI2f / side;
	glBegin(GL_POLYGON);
	for (int i = 0; i < side; i++)
	{
		float x = cos(i * step) * radius;
		float y = sin(i * step) * radius;
		BVectorf vertex = BVectorf(x, y, 0) * quater + center;
		glVertex3f(vertex.x(), vertex.y(), vertex.z());
	}
	glEnd();
}
void BRender::fillCircle(const BVectord& center, double radius, int side, const BVectord& normal)
{
	BQuaterd quater(BVectord(0, 0, 1), normal);
	double step = PI2 / side;
	glBegin(GL_POLYGON);
	for (int i = 0; i < side; i++)
	{
		double x = cos(i * step) * radius;
		double y = sin(i * step) * radius;
		BVectord vertex = BVectord(x, y, 0) * quater + center;
		glVertex3d(vertex.x(), vertex.y(), vertex.z());
	}
	glEnd();
}

void BRender::drawPolygon(const BPolygonf& polygon)
{
	if (polygon.size() > 2)
	{
		glBegin(GL_LINE_LOOP);
		for (int i = 0; i < polygon.size(); i++)
		{
			const BVectorf& v = polygon[i];
			glVertex3f(v.x(), v.y(), v.z());
		}
		glEnd();
	}
}
void BRender::drawPolygon(const BPolygond& polygon)
{
	if (polygon.size() > 2)
	{
		glBegin(GL_LINE_LOOP);
		for (int i = 0; i < polygon.size(); i++)
		{
			const BVectord& v = polygon[i];
			glVertex3d(v.x(), v.y(), v.z());
		}
		glEnd();
	}
}
void BRender::drawPolygon(const BVectorf* points, int size)
{
	if (points && size > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, points);
		glDrawArrays(GL_LINE_LOOP, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::drawPolygon(const BVectord* points, int size)
{
	if (points && size > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, points);
		glDrawArrays(GL_LINE_LOOP, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}

void BRender::drawPolygon(const BVectorfArray& vertices)
{
	if (vertices.size() > 2)
	{
		if (0)
		{
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(3, GL_FLOAT, 0, vertices.data());
			glDrawArrays(GL_LINE_LOOP, 0, vertices.size());
			glDisableClientState(GL_VERTEX_ARRAY);
		}
		glBegin(GL_LINE_LOOP);
		for (int i = 0; i < vertices.size(); i++)
		{
			const BVectorf& v = vertices[i];
			glVertex3f(v.x(), v.y(), v.z());
		}
		glEnd();
	}
}
void BRender::drawPolygon(const BVectorfArray& vertices, const BIndexArray& indices)
{
	glBegin(GL_LINE_LOOP);
	for (int i = 0; i < indices.size(); i++)
	{
		const BVectorf& v = vertices[indices[i]];
		glVertex3f(v.x(), v.y(), v.z());
	}
	glEnd();
}
void BRender::drawPolygon(const BVectordArray& vertices)
{
	if (vertices.size() > 2)
	{
		if (0)
		{
			glEnableClientState(GL_VERTEX_ARRAY);
			glVertexPointer(3, GL_DOUBLE, 0, vertices.data());
			glDrawArrays(GL_LINE_LOOP, 0, vertices.size());
			glDisableClientState(GL_VERTEX_ARRAY);
		}
		glBegin(GL_LINE_LOOP);
		for (int i = 0; i < vertices.size(); i++)
		{
			const BVectord& v = vertices[i];
			glVertex3d(v.x(), v.y(), v.z());
		}
		glEnd();
	}
}
void BRender::drawPolygon(const BVectordArray& vertices, const BIndexArray& indices)
{
	glBegin(GL_LINE_LOOP);
	for (int i = 0; i < indices.size(); i++)
	{
		const BVectord& v = vertices[indices[i]];
		glVertex3d(v.x(), v.y(), v.z());
	}
	glEnd();
}

void BRender::fillPolygon(const BPolygonf& polygon)
{
	if (polygon.size() > 2)
	{
		glBegin(GL_POLYGON);
		for (int i = 0; i < polygon.size(); i++)
		{
			const BVectorf& v = polygon[i];
			glVertex3f(v.x(), v.y(), v.z());
		}
		glEnd();
	}
}
void BRender::fillPolygon(const BPolygond& polygon)
{
	if (polygon.size() > 2)
	{
		glBegin(GL_POLYGON);
		for (int i = 0; i < polygon.size(); i++)
		{
			const BVectord& v = polygon[i];
			glVertex3d(v.x(), v.y(), v.z());
		}
		glEnd();
	}
}
void BRender::fillPolygon(const BVectorf* points, int size)
{
	if (points && size > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, points);
		glDrawArrays(GL_POLYGON, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillPolygon(const BVectord* points, int size)
{
	if (points && size > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, points);
		glDrawArrays(GL_POLYGON, 0, size);
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}

void BRender::fillPolygon(const BVectorfArray& vertices)
{
	if (vertices.size() > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertices.data());
		glDrawArrays(GL_POLYGON, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillPolygon(const BVectordArray& vertices)
{
	if (vertices.size() > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, vertices.data());
		glDrawArrays(GL_POLYGON, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::fillPolygon(const BVectorfArray& vertices, const BIndexArray& indices)
{
	glBegin(GL_POLYGON);
	for (int i = 0; i < indices.size(); i++)
	{
		const BVectorf& v = vertices[indices[i]];
		glVertex3f(v.x(), v.y(), v.z());
	}
	glEnd();
}
void BRender::fillPolygon(const BVectordArray& vertices, const BIndexArray& indices)
{
	glBegin(GL_POLYGON);
	for (int i = 0; i < indices.size(); i++)
	{
		const BVectord& v = vertices[indices[i]];
		glVertex3d(v.x(), v.y(), v.z());
	}
	glEnd();
}

void BRender::drawTriangleFan(const BVectorf* points, int size)
{
	if (points && size > 2)
	{
		glBegin(GL_TRIANGLE_FAN);
		for (int i = 0; i < size; i++)
		{
			const BVectorf& v = points[i];
			glVertex3f(v.x(), v.y(), v.z());
		}
		glEnd();
	}
}
void BRender::drawTriangleFan(const BVectord* points, int size)
{
	if (points && size > 2)
	{
		glBegin(GL_TRIANGLE_FAN);
		for (int i = 0; i < size; i++)
		{
			const BVectord& v = points[i];
			glVertex3d(v.x(), v.y(), v.z());
		}
		glEnd();
	}
}
void BRender::drawTriangleFan(const BVectorfArray& vertices)
{
	if (vertices.size() > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, 0, vertices.data());
		glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}
void BRender::drawTriangleFan(const BVectordArray& vertices)
{
	if (vertices.size() > 2)
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_DOUBLE, 0, vertices.data());
		glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size());
		glDisableClientState(GL_VERTEX_ARRAY);
	}
}

void BRender::drawSpace(const BSpacef& space)
{
	BVectorf v0 = space.v0();
	BVectorf v1 = space.v1();
	BVectorf v2 = space.v2();
	BVectorf v3 = space.v3();
	BVectorf v4 = space.v4();
	BVectorf v5 = space.v5();
	BVectorf v6 = space.v6();
	BVectorf v7 = space.v7();

	drawQuad(v0, v1, v2, v3);
	drawQuad(v4, v5, v6, v7);
	drawLine(v0, v4);
	drawLine(v1, v5);
	drawLine(v2, v6);
	drawLine(v3, v7);
}
void BRender::drawSpace(const BSpaced& space)
{
	BVectord v0 = space.v0();
	BVectord v1 = space.v1();
	BVectord v2 = space.v2();
	BVectord v3 = space.v3();
	BVectord v4 = space.v4();
	BVectord v5 = space.v5();
	BVectord v6 = space.v6();
	BVectord v7 = space.v7();

	drawQuad(v0, v1, v2, v3);
	drawQuad(v4, v5, v6, v7);
	drawLine(v0, v4);
	drawLine(v1, v5);
	drawLine(v2, v6);
	drawLine(v3, v7);
}

void BRender::fillSpace(const BSpacef& space)
{
	BVectorf v0 = space.v0();
	BVectorf v1 = space.v1();
	BVectorf v2 = space.v2();
	BVectorf v3 = space.v3();
	BVectorf v4 = space.v4();
	BVectorf v5 = space.v5();
	BVectorf v6 = space.v6();
	BVectorf v7 = space.v7();

	if (member.lighting)
	{
		glNormal3f(0.0f, 0.0f, -1.0f);
		fillQuad(v3, v2, v1, v0);
		glNormal3f(0.0f, 0.0f, 1.0f);
		fillQuad(v4, v5, v6, v7);
		glNormal3f(0.0f, -1.0f, 0.0f);
		fillQuad(v0, v1, v5, v4);
		glNormal3f(1.0f, 0.0f, 0.0f);
		fillQuad(v1, v2, v6, v5);
		glNormal3f(0.0f, 1.0f, 0.0f);
		fillQuad(v2, v3, v7, v6);
		glNormal3f(-1.0f, 0.0f, 0.0f);
		fillQuad(v3, v0, v4, v7);
	}
	else
	{
		fillQuad(v3, v2, v1, v0);
		fillQuad(v4, v5, v6, v7);
		fillQuad(v0, v1, v5, v4);
		fillQuad(v1, v2, v6, v5);
		fillQuad(v2, v3, v7, v6);
		fillQuad(v3, v0, v4, v7);
	}
}
void BRender::fillSpace(const BSpaced& space)
{
	BVectord v0 = space.v0();
	BVectord v1 = space.v1();
	BVectord v2 = space.v2();
	BVectord v3 = space.v3();
	BVectord v4 = space.v4();
	BVectord v5 = space.v5();
	BVectord v6 = space.v6();
	BVectord v7 = space.v7();

	if (member.lighting)
	{
		glNormal3d(0.0, 0.0, -1.0);
		fillQuad(v3, v2, v1, v0);
		glNormal3d(0.0, 0.0, 1.0);
		fillQuad(v4, v5, v6, v7);
		glNormal3d(0.0, -1.0, 0.0);
		fillQuad(v0, v1, v5, v4);
		glNormal3d(1.0, 0.0, 0.0);
		fillQuad(v1, v2, v6, v5);
		glNormal3d(0.0, 1.0, 0.0);
		fillQuad(v2, v3, v7, v6);
		glNormal3d(-1.0, 0.0, 0.0);
		fillQuad(v3, v0, v4, v7);
	}
	else
	{
		fillQuad(v3, v2, v1, v0);
		fillQuad(v4, v5, v6, v7);
		fillQuad(v0, v1, v5, v4);
		fillQuad(v1, v2, v6, v5);
		fillQuad(v2, v3, v7, v6);
		fillQuad(v3, v0, v4, v7);
	}
}

void BRender::drawBox(const BBoxf& box)
{
	BVectorf v0 = box.v0();
	BVectorf v1 = box.v1();
	BVectorf v2 = box.v2();
	BVectorf v3 = box.v3();
	BVectorf v4 = box.v4();
	BVectorf v5 = box.v5();
	BVectorf v6 = box.v6();
	BVectorf v7 = box.v7();

	drawQuad(v0, v1, v2, v3);
	drawQuad(v4, v5, v6, v7);
	drawLine(v0, v4);
	drawLine(v1, v5);
	drawLine(v2, v6);
	drawLine(v3, v7);
}
void BRender::drawBox(const BBoxd& box)
{
	BVectord v0 = box.v0();
	BVectord v1 = box.v1();
	BVectord v2 = box.v2();
	BVectord v3 = box.v3();
	BVectord v4 = box.v4();
	BVectord v5 = box.v5();
	BVectord v6 = box.v6();
	BVectord v7 = box.v7();

	drawQuad(v0, v1, v2, v3);
	drawQuad(v4, v5, v6, v7);
	drawLine(v0, v4);
	drawLine(v1, v5);
	drawLine(v2, v6);
	drawLine(v3, v7);
}

void BRender::fillBox(const BBoxf& box)
{
	BVectorf v0 = box.v0();
	BVectorf v1 = box.v1();
	BVectorf v2 = box.v2();
	BVectorf v3 = box.v3();
	BVectorf v4 = box.v4();
	BVectorf v5 = box.v5();
	BVectorf v6 = box.v6();
	BVectorf v7 = box.v7();

	fillQuad(v3, v2, v1, v0);
	fillQuad(v4, v5, v6, v7);
	fillQuad(v0, v1, v5, v4);
	fillQuad(v1, v2, v6, v5);
	fillQuad(v2, v3, v7, v6);
	fillQuad(v3, v0, v4, v7);
}
void BRender::fillBox(const BBoxd& box)
{
	BVectord v0 = box.v0();
	BVectord v1 = box.v1();
	BVectord v2 = box.v2();
	BVectord v3 = box.v3();
	BVectord v4 = box.v4();
	BVectord v5 = box.v5();
	BVectord v6 = box.v6();
	BVectord v7 = box.v7();

	fillQuad(v3, v2, v1, v0);
	fillQuad(v4, v5, v6, v7);
	fillQuad(v0, v1, v5, v4);
	fillQuad(v1, v2, v6, v5);
	fillQuad(v2, v3, v7, v6);
	fillQuad(v3, v0, v4, v7);
}

void BRender::drawShape(const BShape* shape)
{
	if (shape == 0)
		return;
	if (shape_member(shape)->dirty)
	{
		shape->flush();
	}
	glPushMatrix();
	glPushAttrib(GL_ALL_ATTRIB_BITS);

	setLighting(shape_member(shape)->lighting);
	setDepthTest(shape_member(shape)->depthTest);
	setCullback(shape_member(shape)->cullback);
	setLineSmooth(shape_member(shape)->lineSmooth);
	setPointSmooth(shape_member(shape)->pointSmooth);
	setLineWidth(shape_member(shape)->lineWidth);
	setPointSize(shape_member(shape)->pointSize);
	setPolyMode(shape_member(shape)->polyMode);

	if (member.lighting && member.lights)
	{
		member.useLights(shape->space().center());
		const BMaterial* material = shape_member(shape)->material;
		if (material)
		{
			setMaterial(material);
			glDisable(GL_COLOR_MATERIAL);
		}
		else
		{
			glEnable(GL_COLOR_MATERIAL);
		}
	}
	else
	{
		glDisable(GL_COLOR_MATERIAL);
	}

	const BMatrix& matrix = shape_member(shape)->matrix;
	BOpenGL::glMultMatrix(matrix);

	const BVector scale = matrix.scale();
	BOpenGL::glScale(scale.x(), scale.y(), scale.z());

	const BProgram* program = shape_member(shape)->program;
	setProgram(program);

	const BColor& color = shape_member(shape)->color;
	setColor(color);

	if (shape_member(shape)->textures.size())
	{
		BArray<BTextureHolder>& textures = shape_member(shape)->textures;
		for (int i = 0; i < textures.size(); i++)
		{
			BTexture* texture = textures[i];
			setTexture(texture, i);
		}
	}

	shape_member(shape)->render(*this);

	if (program)
		setProgram(0);

	glPopAttrib();
	glPopMatrix();
}
